package com.powernode.listener;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.powernode.constant.Constants;
import com.powernode.entity.Orders;
import com.powernode.service.OrdersService;
import com.powernode.service.message.DelayMessageService;
import com.rabbitmq.client.Channel;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.io.IOException;
import java.security.Key;

/**
 * 下订单 消费者 监听器类
 */
@Component
@Slf4j
public class OrderRabbitListener {

    @Resource
    private ObjectMapper objectMapper;

    @Resource
    private OrdersService ordersService;

    @Resource
    private RedisTemplate redisTemplate;

    @Resource
    private DelayMessageService delayMessageService;

    /**
     * 定义消费者
     * 指定监听队列 和 指定线程数量
     *
     * @param message
     * @param channel
     */
    @RabbitListener(queues = Constants.QUEUE_NAME_ORDER, concurrency = "4")
    public void handlerOrderMsg(Message message, Channel channel) {
        log.info("service模块作为消费者 接收传入的 orders消息数据");
        try {
            // 将消息转换成 orders类型实例数据  --> 使用 ObjectMapper
            Orders orders = objectMapper.readValue(message.getBody(), Orders.class);
            // 将 订单信息传送 继续进行下订单功能   --->  调用 service业务层的 下订单功能
            int orderResult = ordersService.doOrder(orders);

            // 将订单主键自增回填的 订单id 发送延迟消息 --> 超时未支付功能的 判断订单状态
            delayMessageService.sendDelayMsg(orders.getId());

            // 如果结果返回 > 0 ===> 则说明下订单成功
            // TODO : 是所有订单都传给redis , 还是只有下单成功的才传
            if (orderResult > 0) {
                // 将 订单信息 放入到redis中 , 减轻数据库的压力
                // 通过 商品id 和 用户id 锁定对应值
                String key = Constants.REDIS_RESULT + orders.getGoodsId() + ":" + orders.getUid();
                redisTemplate.opsForValue().set(key , orders);
                // 手动签收
                channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
                return;
            }
            // 手动签收 , 但不确认
            channel.basicNack(message.getMessageProperties().getDeliveryTag(), false, true);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
}
